#ifndef SERVER_H
#define SERVER_H

#include <QObject>
#include <QHttpServer>
#include <QProtobufSerializer>
#include <QTcpServer>
#include <QWebSocketServer>
#include <QWebSocket>
#include <QUuid>
#include <QIcon>
#include <QPixmap>
#include <QFileInfo>
#include <QFile>
#include <QRandomGenerator>

#include "base.qpb.h"
#include "file.qpb.h"
#include "friend.qpb.h"
#include "gateway.qpb.h"
#include "message.qpb.h"
#include "notify.qpb.h"
#include "speech.qpb.h"
#include "transmite.qpb.h"
#include "user.qpb.h"

//////////////////////////////////////
/// utility function
//////////////////////////////////////

// generate uuid
static inline QString makeId() {
    return "M" + QUuid::createUuid().toString().sliced(25, 12);
}

// get timestamp
static inline qint64 getTime() {
    return QDateTime::currentSecsSinceEpoch();
}

// convert timestamp to formatted time
static inline QString formatTime(qint64 timestamp) {
    QDateTime time = QDateTime::fromSecsSinceEpoch(timestamp);
    return time.toString("MM/dd hh:mm");
}

// convert QByteArray to QIcon
static inline QIcon makeIcon(const QByteArray& data) {
    QPixmap pixmap;
    pixmap.loadFromData(data);
    return QIcon(pixmap);
}

// file operation
// read QByteArray from file
static inline QByteArray readByteArrayFromFile(const QString& path) {
    QFile file(path);
    bool ok = file.open(QFile::ReadOnly);
    if(!ok) {
        qDebug() << "open file failed: " << file.errorString();
        return QByteArray();
    }
    return file.readAll();
}

// write QByteArray into file
static inline void writeByteArrayToFile(const QString& path, const QByteArray& data) {
    QFile file(path);
    bool ok = file.open(QFile::WriteOnly);
    if(!ok) {
        qDebug() << "打开文件失败!";
        return;
    }
    file.write(data);
    file.flush();
}

// get file name
static inline QString getFileName(const QString& path) {
    QFileInfo info(path);
    return info.fileName();
}

// logging print
#define TAG QString("[%1:%2]").arg(getFileName(__FILE__), QString::number(__LINE__))
#define LOG() qDebug().noquote() << TAG

// make UserInfo
static bite_im::UserInfo makeUserInfo()
{
    bite_im::UserInfo userInfo;
    QVector<QString> v({"luffy", "zoro", "usopp", "nami", "sanji", "chopper",
                        "robin", "franky", "brook", "jinbe"});
    int n = v.size();
    int index = QRandomGenerator::global()->bounded(n);
    userInfo.setUserId("1234");
    userInfo.setNickname(v[index]);
    userInfo.setAvatar(readByteArrayFromFile(":/resource/image/" + v[index] + ".png"));
    userInfo.setPhone("15912345678");
    userInfo.setDescription("become the pirate king");
    return userInfo;
}

// make UserInfo
static bite_im::UserInfo makeUserInfo(int pos)
{
    bite_im::UserInfo userInfo;
    QVector<QString> v({"luffy", "zoro", "usopp", "nami", "sanji", "chopper",
                        "robin", "franky", "brook", "jinbe"});
    int n = v.size();
    int index = QRandomGenerator::global()->bounded(n);
    userInfo.setUserId(QString::number(1234 + pos));
    userInfo.setNickname("luffy" + QString::number(pos));
    userInfo.setAvatar(readByteArrayFromFile(":/resource/image/" + v[index] + ".png"));
    userInfo.setPhone("15912345678");
    userInfo.setDescription("become the pirate king");
    return userInfo;
}

// make TextMessage
static bite_im::MessageContent makeTextMessage()
{
    bite_im::StringMessageInfo info;
    info.setContent("this is a content");

    bite_im::MessageContent msg;
    msg.setMessageType(bite_im::MessageTypeGadget::MessageType::STRING);
    msg.setStringMessage(info);
    return msg;
}

// make MessageInfo from the specified chatSessionId
static bite_im::MessageInfo makeMessageInfo(const QString& chatSessionId)
{
    bite_im::MessageInfo msgInfo;
    msgInfo.setMessageId(makeId());
    msgInfo.setChatSessionId(chatSessionId);
    msgInfo.setTimestamp(getTime());
    msgInfo.setSender(makeUserInfo(QRandomGenerator::global()->bounded(0, 20)));
    msgInfo.setMessage(makeTextMessage());

    return msgInfo;
}

// make ChatSessionInfo
static bite_im::ChatSessionInfo makeChatSessionInfo(int pos)
{
    bite_im::ChatSessionInfo info;
    info.setChatSessionId(QString::number(1234 + pos));
    info.setChatSessionName("session" + QString::number(pos));
    info.setAvatar(readByteArrayFromFile(":/resource/image/luffy.png"));
    info.setPrevMessage(makeMessageInfo("1234"));
    info.setSingleChatFriendId(QString::number(1234 + pos));

    return info;
}

//////////////////////////////////////////////
/// HTTP 服务器
//////////////////////////////////////////////

class HttpServer : public QObject
{
    Q_OBJECT
public:
    static HttpServer* getInstance();

    // the initialization of server
    void init();

    // construct UserInfo and send back to client
    QHttpServerResponse getUserInfo(const QHttpServerRequest& req);

    // construct FriendList and send back to client
    QHttpServerResponse getFriendList(const QHttpServerRequest& req);

    // construct ChatSessionList and send back to client
    QHttpServerResponse getChatSessionList(const QHttpServerRequest& req);

    // construct ApplyList and send back to client
    QHttpServerResponse getApplyList(const QHttpServerRequest& req);

    // construct RecentMessage of specified chatSessionId and send back to client
    QHttpServerResponse getRecentMessage(const QHttpServerRequest& req);

    QHttpServerResponse getNewMessage(const QHttpServerRequest& req);

    QHttpServerResponse getNickname(const QHttpServerRequest& req);

    QHttpServerResponse getDescription(const QHttpServerRequest& req);

    QHttpServerResponse getVerifyCode(const QHttpServerRequest& req);

    QHttpServerResponse getPhone(const QHttpServerRequest& req);

    QHttpServerResponse getAvatar(const QHttpServerRequest& req);

    QHttpServerResponse deleteFriend(const QHttpServerRequest& req);

    QHttpServerResponse addFriendApply(const QHttpServerRequest& req);

    QHttpServerResponse addFriendProcess(const QHttpServerRequest& req);

    QHttpServerResponse createChatSession(const QHttpServerRequest& req);
private:
    HttpServer();

    static HttpServer* instance;

    QHttpServer httpServer;
    QProtobufSerializer serializer;
};

//////////////////////////////////////////////
/// Websocket 服务器
//////////////////////////////////////////////

class WebsocketServer : public QObject
{
    Q_OBJECT
public:
    static WebsocketServer* getInstance();

    // initialize Websocket server
    bool init();

private:
    static WebsocketServer* instance;

    WebsocketServer();

    QWebSocketServer wsServer;
    QProtobufSerializer serializer;

signals:
    void sendMessageToClient();
    void sendDeleteFriendToClient();
    void sendFriendApplyToClient();
    void agreeFriendApplyToClient();
    void rejectFriendApplyToClient();
    void createChatSessionToClient();
};

#endif // SERVER_H
